﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using EbbinghausWord.Common;
using EbbinghausWord.DAL;
using EbbinghausWord.Entities;

namespace EbbinghausWord.BLL
{
    /// <summary>
    /// 词典管理类
    /// </summary>
    public static class DictionaryManager
    {
        #region private filed

        /// <summary>
        /// 单词词典
        /// </summary>
        private static readonly Dictionary<string, TableDictionaryEntity> _wordDictionary =
            new Dictionary<string, TableDictionaryEntity>();

        private static AutoResetEvent _resetEvent = new AutoResetEvent(false);

        /// <summary>
        /// 字母加载 集合
        /// </summary>
        private static Dictionary<string, bool> _letters = new Dictionary<string, bool>()  {
                                  {"a", false},
                                  {"b", false},
                                  {"c", false},
                                  {"d", false},
                                  {"e", false},
                                  {"f", false},
                                  {"g", false},
                                  {"h", false},
                                  {"i", false},
                                  {"j", false},
                                  {"k", false},
                                  {"l", false},
                                  {"m", false},
                                  {"n", false},
                                  {"o", false},
                                  {"p", false},
                                  {"q", false},
                                  {"r", false},
                                  {"s", false},
                                  {"t", false},
                                  {"u", false},
                                  {"v", false},
                                  {"w", false},
                                  {"x", false},
                                  {"y", false},
                                  {"z", false},
};
        #endregion

        #region public method

        /// <summary>
        /// 初始化数据库字典
        /// </summary>
        public static void InitDb()
        {
            //从xml文件中生成
            var et = new ExecuteTimer(false);

            SysDataContext.CreateDb();
            et.Show("CreateDb");

            //InitDictionaryFile();
            InitDictAsync();
            et.Show("InitDict");

            BookDAL.InitCurrentBookWord();
            et.Show("InitCurrentBookWord");
        }

        /// <summary>
        /// 根据英文，获得单词含义
        /// </summary>
        /// <param name="english"></param>
        /// <returns></returns>
        public static DictionaryWord GetWord(string english)
        {
            try
            {
                //字典队列中是否存在该单词
                if (_wordDictionary.ContainsKey(english))
                {
                    return DictionaryWord.FromXElement(_wordDictionary[english].CompleteData);
                }
                else
                {
                    //该单词的首字母，在字母队列中，是否加载完成
                    if (IsWordFirstLetterLoaded(english))
                    {
                        //检查 并 获得单词实体
                        return CheckAndGetWordDictionary(english);
                    }
                    else
                    {
                        Debug.WriteLine("Enqueue :" + english);
                        //将该单词首字母的小写，设置为“优先字母”
                        _resetEvent = new AutoResetEvent(false);
                        PriorLetter = english[0].ToString().ToLower();


                        //耐心等待之
                        _resetEvent.WaitOne(2000);

                        Debug.WriteLine("Get Chinese for " + english);

                        //检查 并 获得单词实体
                        return CheckAndGetWordDictionary(english);
                    }
                }
            }
            catch (Exception)
            {
                //返回空对象实体
                return DictionaryWord.CreateEmptyEntity(english);
            }
        }

        /// <summary>
        /// 检查 并 获得单词实体
        /// </summary>
        /// <param name="english"></param>
        /// <returns></returns>
        private static DictionaryWord CheckAndGetWordDictionary(string english)
        {
            //再次从字典队列中检查是否存在该单词
            return _wordDictionary.ContainsKey(english)
                ? DictionaryWord.FromXElement(_wordDictionary[english].CompleteData)
                : DictionaryWord.CreateEmptyEntity(english);
        }

        #endregion

        #region public property

        /// <summary>
        /// 优先加载的字母
        /// </summary>
        public static string PriorLetter { get; set; }
        #endregion

        #region private method

        /// <summary>
        /// 初始化字典文件
        /// </summary>
        private static void InitDictionaryFile()
        {
            var et = new ExecuteTimer(false);

            //打开词典文件
            var works = XElement.Load(@"words/dictionary.xml");
            et.Show("LoadFile");

            //初始化词典
            foreach (var element in works.Elements())
            {
                var english = element.Element("E").Value;

                _wordDictionary.Add(english,
                    new TableDictionaryEntity()
                    {
                        English = english,
                        CompleteData = element,
                    });

                //DictionaryWord.FromXElementString(element.ToString());
            }
            et.Show("Init");
        }

        /// <summary>
        /// 异步初始化词典
        /// </summary>
        private static void InitDictAsync()
        {
            //优先加载队列中的单词
            if (new UserConfig().SerielizeQueueWord != string.Empty)
            {
                PriorLetter = new UserConfig().SerielizeQueueWord[0].ToString().ToLower();
            }

            //启动异步加载词典的线程
            new Thread(InitDict).Start();
        }

        /// <summary>
        /// 初始化字典
        /// </summary>
        private static void InitDict()
        {
            while (true)
            {
                //是否有“优先字母”, 优先字母是否加载完成，否则加载
                if (PriorLetter != null && !_letters[PriorLetter])
                {
                    //加载字典内容
                    LoadContent(PriorLetter);

                    Debug.WriteLine("Send event about letter : " + PriorLetter);
                    //发送通知 加载完成
                    _resetEvent.Set();

                    //将优先字母设置为空
                    PriorLetter = null;
                }
                else
                {
                    //是否还有未加载的字母
                    if (_letters.Any(x => !x.Value))
                    {
                        //加载字典内容
                        var forLoadLetter = _letters.FirstOrDefault(x => !x.Value).Key;
                        LoadContent(forLoadLetter);
                    }
                    else
                    {
                        //加载完成，退出
                        break;
                    }
                }

                //放慢速度，便于测试
                //Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 加载字典内容
        /// </summary>
        /// <param name="letter"></param>
        private static void LoadContent(string letter)
        {
            //打开字母对应的文件
            var works = XElement.Load(@"words/dictionary/" + letter + ".xml");

            //将其初始化到指定的字典对象中
            foreach (var element in works.Elements())
            {
                var english = element.Element("E").Value;

                _wordDictionary.Add(english,
                                    new TableDictionaryEntity()
                                        {
                                            English = english,
                                            CompleteData = element,
                                        });
            }

            //加载完成，该字母标记为已经加载
            _letters[letter] = true;
        }

        /// <summary>
        /// 单词是否加载完成
        /// </summary>
        /// <param name="english"></param>
        /// <returns></returns>
        private static bool IsWordFirstLetterLoaded(string english)
        {
            return _letters[english[0].ToString().ToLower()];
        }

        #endregion
    }
}